#ifndef _REACTOR_HPP
#define _REACTOR_HPP

#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <memory>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <error.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>

/*
 * 实现ET工作方式的epoll模型(非阻塞)
 * Rector封装
 * LT(阻塞和非阻塞都可以)
*/

class Event;
class Reactor;

// 回调函数处理事件
typedef int (*epoll_callback_t)(Event* event);

class Event
{
public:
    // epoll事件
    struct epoll_event _event;

    // 缓冲区设置
    std::string _in_buffer;
    std::string _out_buffer;
  
    // 回调处理方法
    epoll_callback_t _recv;
    epoll_callback_t _send;
    epoll_callback_t _error;

    // 回指Reactor
    Reactor *_R;

    // 对应的fd
    int _sock;

    Event()
      :_recv(nullptr), _send(nullptr), _error(nullptr), _R(nullptr), _sock(-1)
    {}

    void RegisterCallback(epoll_callback_t recv, epoll_callback_t send, epoll_callback_t error)
    {
        _recv = recv;
        _send = send;
        _error = error;
    }
};

class Reactor
{
public:
    const int NUM = 1024;
    const int SIZE = 1024;
    int _epfd;
    // 可以不需要，因为epoll_event中有字段data里的ptr，可以回指Event
    std::unordered_map<int, Event*> _events_map;

    Reactor()
      :_epfd(-1)
    {}

    bool InitReactor()
    {
        _epfd = epoll_create(SIZE);
        if(_epfd == -1)
        {
            fprintf(stdout, "epoll_create: %s\n", strerror(errno));
            return false;
        }
      
        fprintf(stdout, "Initializing reactor succed!\n");
        return true;
    }

    bool InsertEvent(Event* event, uint32_t cmd)
    {
        if(_epfd == -1)
        {
            fprintf(stderr, "uninitializing Reactor!\n");
            return false;
        }

        // 构造ev，插入对应的Event中
        struct epoll_event ev;
        ev.events = cmd;
        ev.data.fd = event->_sock;
        event->_event = ev;
        if(epoll_ctl(_epfd, EPOLL_CTL_ADD, event->_sock, &ev) == -1)
        {
            fprintf(stderr, "epoll_ctl: %s\n", strerror(errno));
            return false;
        }

        _events_map.insert({event->_sock, event});
        fprintf(stdout, "InserEvent succeed!\n");
        return true;
    }

    void _Dispatch(struct epoll_event* revents, int n)
    {
        assert(revents); 
        for(int i = 0; i < n; ++i)
        {
            // 通过map映射找到对应的Event*
            Event* event = _events_map[revents[i].data.fd];
            uint32_t cmd = revents[i].events;
            // 错误事处理件
            if(cmd & EPOLLERR) cmd |= (EPOLLIN | EPOLLOUT);
            // 挂起事件处理
            if(cmd & EPOLLHUP) cmd |= (EPOLLIN | EPOLLOUT);

            // 读事件处理
            if(cmd & EPOLLIN)
            {
                if(_events_map.find(event->_sock) != _events_map.end() && event->_recv)
                {
                    fprintf(stdout, "有读事件到来!\n");
                    event->_recv(event);
                }
            }

            // 写事件处理
            if(cmd & EPOLLOUT)
            {
                fprintf(stdout, "有写事件到来!\n");
                if(_events_map.find(event->_sock) != _events_map.end() && event->_send)
                {
                  event->_send(event);
                }
            }
        }
    }

    // 事件派发器
    void Dispatcher(int timeout)
    {
        struct epoll_event revents[NUM];
        int n = epoll_wait(_epfd, revents, NUM, timeout);
        switch(n)
        {
            case -1:
              fprintf(stderr, "epoll_wait: %s\n", strerror(errno));
              break;
            case 0:
              fprintf(stdout, "timeout!\n");
              break;
            default:
              _Dispatch(revents, n);
        }

        
    }

    bool EnableAbility(int fd, bool read_ability, bool write_ability)
    {
        struct epoll_event ev;
        ev.events = (read_ability? EPOLLIN : 0) | (write_ability? EPOLLOUT : 0);
        ev.data.fd = fd;
        if(epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &ev) == -1)
        {
            fprintf(stderr, "epoll_ctl: %s\n", strerror(errno));
            return false;
        }

        return true;
    }

    void DeleteEvent(Event* delete_event)
    {
        std::unordered_map<int, Event*>::iterator it = _events_map.find(delete_event->_sock);
        if(it != _events_map.end())
        {
            fprintf(stdout, "fd not exits!\n");
            return;
        }

        // 从映射中删除
        _events_map.erase(it);
        // 从epoll中删除
        if(epoll_ctl(_epfd, EPOLL_CTL_DEL, delete_event->_sock, &delete_event->_event) == -1)
        {
            fprintf(stderr, "epoll_ctl: %s\n", strerror(errno));
            return;
        }
        // 关闭文件描述符
        close(delete_event->_sock);
        // 释放内存
        delete delete_event;
        delete_event = nullptr;
        fprintf(stdout, "Delete succed!\n");
    }

    ~Reactor()
    {
        _epfd = -1;
    }
};


#endif
